package RecognizeFinger;
import java.util.ArrayList;



public class Fingerprint {

	// DO NOT write FFT.WINDOW_SIZE / 44100, it equals to 0 forever!!
    public static final double scaling = FFT.WINDOW_SIZE / 44100.0;

    public static final int N = 3;

    private ArrayList<int[]> constel_data = new ArrayList<>();
    private int id;

    /**
     * For songs about to add into DB
     * @param id
     */
    public Fingerprint(int id) {
        this.id = id;
    }

    /**
     * For songs about to be searched
     */
    public Fingerprint() {
        this.id = -1;
    }

    /**
     * Append a column of frequency peaks to the constellation map.
     * A frequency peak is a frequency value whose amplitude is the highest among
     * all frequencies in a frequency interval.
     *
     * @param freqDomain The frequency domain generated by FFT.
     */
    public void append(double[] freqDomain) {
        int[] freqPeaks = new int[N];
        
        /**
         * TODO: Either find N frequencies with the highest amplitude(energy),
         * or find the frequency with the max energy within each interval.
         */
        int i = 0;
        for (double value : freqDomain) {
        	if (i > 511) break;
        	if (i < N) {
        		freqPeaks[i] = i;
        		if (i == N -1) {
        			sort(freqDomain, freqPeaks);
        		}
        	} else {
        		if (value > freqDomain[freqPeaks[0]]) {
        			freqPeaks[0] = i;
    				sort(freqDomain, freqPeaks);
    				break;
    			}
        	}
        	i++;
        }
        constel_data.add(freqPeaks);
    }
    private void sort(double[] freqDomain, int[] freqPeaks) { 
        int j;
        int i;    
        int key;         
        for( j = 1; j < N; j++){  
            key=freqPeaks[j];  
            i = j - 1;  
            while(i >= 0 && freqDomain[freqPeaks[i]] > freqDomain[key]){  
                freqPeaks[i+1] = freqPeaks[i]; 
                i--;          
            }
            freqPeaks[i+1] = key; 
        }  
    }
    /**
     * Generate fingerprints using Combinational Hash.
     * For each frequency peak, generate 6 fingerprints with its 6 successors.
     *
     * @return
     */
    public ArrayList<ShazamHash> combineHash() {
       if (constel_data.size() < 3)
                throw new RuntimeException("Too few frequency peaks");
        ArrayList<ShazamHash> hashes = new ArrayList<>();
        for (int i = 0; i < constel_data.size() - 2; ++i) {
            for (int k = 0; k < N; ++k) {

            	// "Combine" with all peak frequencies inside its next two frames.
                for (int j = 1; j <= 2; ++j) {
                    for (int kk = 1; kk < N; ++kk) {
                        ShazamHash hash = new ShazamHash();
                        short f1 = (short) constel_data.get(i)[k];
                        short f2 = (short) constel_data.get(i + j)[kk];
                        short dt = (short) j;
                        hash.fingerId = (dt<<18) | (f1<<9) | f2;
                        hash.offset = i;
                        hash.id = id;
                        hashes.add(hash);
                    }
                }
            }
        }
        return hashes;
    }
	
}
